﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Microsoft.FxCop.Sdk;
using System.Configuration;


    public class ConfigKeyExistsInConfig : ConfigurationIntrospectionRule
    {
        private HashSet<string> _ConfigKeys = new HashSet<string>(StringComparer.InvariantCulture);

        public ConfigKeyExistsInConfig() : base("ConfigKeyExistsInConfig") 
        {
            
        }

       
      
        public override ProblemCollection Check(Resource resource)
        {
            Debug.WriteLine("Resource:"+resource.Name);

            return base.Check(resource);
        }
        //public override void Visit(Node node)
        //{
        //   // Debug.WriteLine("Visiting:"+node.NodeType);
        //    base.Visit(node);
        //}
        //public override ProblemCollection Check(Microsoft.FxCop.Sdk.Member member)
        //{
        //    Debug.Assert(_ConfigProbingStarted ==true);
        //    Debug.Assert(_ConfigProbingStopped == true);
        //    //Debug.WriteLine(member.DeclaringType.DeclaringModule.Directory);
        //    //Debug.WriteLine(member.DeclaringType.DeclaringModule.Location);
        //    ////Debug.WriteLine(member.DeclaringType.DeclaringModule.ContainingAssembly.);
        //    //Debug.WriteLine(member.DeclaringType.DeclaringModule.Location);
        //    if (member is PropertyNode)
        //        VisitProperty((PropertyNode)member);
        //    if (member is Field)
        //        VisitField((Field)member);
        //    if (member is Method)
        //        VisitMethod((Method)member);
        //    return Problems;
        //}
        //public override void VisitProperty(PropertyNode property)
        //{
        //    Debug.WriteLine("Property:" + property.FullName + ":" + property.OtherMethods.Count);
        //    base.VisitProperty(property);
            

        //}
        public override void VisitMethod(Method method)
        {
            base.VisitMethod(method);
            var prevInstructions = new Stack<Instruction>();
            foreach (var instruction in method.Instructions)
            {
                
                  //L_0000: call class [System]System.Collections.Specialized.NameValueCollection [System.Configuration]System.Configuration.ConfigurationManager::get_AppSettings()
                  //L_0005: ldc.i4.1 
                  //L_0006: callvirt instance string [System]System.Collections.Specialized.NameValueCollection::get_Item(int32)

                  //L_0025: call class [System]System.Collections.Specialized.NameValueCollection [System.Configuration]System.Configuration.ConfigurationManager::get_AppSettings()
                  //L_002a: ldstr "test2"
                    //L_002f: callvirt instance string [System]System.Collections.Specialized.NameValueCollection::get_Item(string)

                if (instruction.OpCode == OpCode.Callvirt && instruction.Value is Method)
                {
                    var instructionMethod = instruction.Value as Method;
                    if(instructionMethod.FullName.StartsWith("System.Collections.Specialized.NameValueCollection.get_Item") && prevInstructions.Count>1)
                    {
                        var arg=prevInstructions.Pop();
                        var configInstruction = prevInstructions.Pop();
                        if (Debugger.IsAttached)
                        {
                            Debug.Assert(configInstruction.Value is Method);
                            if (configInstruction.Value is Method)
                                Debug.Assert((configInstruction.Value as Method).FullName.StartsWith("System.Configuration.ConfigurationManager.get_AppSettings"));
                        }
                        //if(configInstruction.Value is Method && (configInstruction.Value as Method).FullName.StartsWith("System.Configuration.ConfigurationManager.get_AppSettings"))
                        VisitConfigurationCall(method, configInstruction, arg);
                        continue;
                    }
                    //.FullName.StartsWith("System.Configuration.ConfigurationManager")
                }
                //Visit(instruction);
                if (instruction.OpCode != OpCode.Nop)
                    prevInstructions.Push(instruction);
            }

        }

        private void VisitConfigurationCall(Method method, Instruction config, Instruction arg)
        {
            
            Debug.WriteLine(method.FullName+":Accessor?"+method.IsAccessor);
            bool exists=false;
            if (arg.Value is int && ((int)arg.Value) < _ConfigKeys.Count)
            {
                exists = true;
            }
            else if (arg.Value is string && _ConfigKeys.Contains((string)arg.Value))
            {
                exists = true;
            }
 if(exists==false)
            Problems.Add(new Problem(GetResolution(arg.Value.ToString()), arg));
        }
        
        //public override visitmet
        public override ProblemCollection Check(ModuleNode module, Configuration configuration)
        {
            foreach (var setting in configuration.AppSettings.Settings.AllKeys)
            {
                _ConfigKeys.Add(setting);
            }
            VisitTypeNodes(module.Types);

            return Problems;
        }
    }

